package wiki.xsx.core.bytecode.transformer;

import javassist.CtBehavior;
import javassist.CtClass;
import javassist.bytecode.MethodInfo;
import wiki.xsx.core.bytecode.enums.ExecuteType;
import wiki.xsx.core.bytecode.model.Annotations;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 抽象方法注解转换器
 *
 * @author xsx
 * @date 2023/3/2
 * @since 1.8
 * <p>
 * Copyright (c) 2023 xsx All Rights Reserved.
 * easy-bytecode is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
public abstract class AbstractMethodAnnotationTransformer extends AbstractAnnotationTransformer {

    /**
     * 方法参数类型
     */
    protected List<Class<?>> parameterTypes;
    /**
     * 执行类型
     */
    protected ExecuteType executeType;
    /**
     * 注解数组
     */
    protected Annotations[] annotations;

    /**
     * 有参构造
     *
     * @param isWrite    是否写入
     * @param fileDir    文件目录
     * @param className  类名称
     * @param methodName 方法名称
     */
    public AbstractMethodAnnotationTransformer(
            Boolean isWrite,
            String fileDir,
            ExecuteType executeType,
            String className,
            String methodName,
            List<Class<?>> parameterTypes,
            Annotations... annotations
    ) {
        super(isWrite, fileDir, className, methodName);
        this.parameterTypes = Optional.ofNullable(parameterTypes).orElse(new ArrayList<>(0));
        this.executeType = executeType;
        this.annotations = Optional.ofNullable(annotations).orElse(new Annotations[0]);
    }

    /**
     * 处理
     *
     * @param ctClass    ct类
     * @param ctBehavior ct行为
     */
    protected void process(CtClass ctClass, CtBehavior ctBehavior) {
        this.process(ctClass, ctBehavior.getMethodInfo());
    }

    /**
     * 处理
     *
     * @param ctClass ct类
     * @param methodInfo  方法信息
     */
    private void process(CtClass ctClass, MethodInfo methodInfo) {
        switch (this.executeType) {
            // 新增或更新
            case ANNOTATION_METHOD_ADD_OR_UPDATE: {
                this.addOrUpdateAnnotation(methodInfo, ctClass.getClassFile().getConstPool(), this.annotations).forEach(methodInfo::addAttribute);
                break;
            }
            // 移除
            case ANNOTATION_METHOD_REMOVE: {
                this.removeAnnotation(methodInfo, this.annotations);
                break;
            }
        }
    }
}
